package my.org.swing.date;

import java.time.LocalDate;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
import javax.swing.table.AbstractTableModel;

class DateModel extends AbstractTableModel {

    private static final long serialVersionUID = -7293781671409594691L;

    private int mode;

    private LocalDate calendar;

    private int firstLocation;

    private int offset;

    public DateModel(int mode, LocalDate calendar) {
        this.mode = mode;
        this.calendar = calendar;
        changeMonth(calendar);
    }

    public void changeMonth(LocalDate newDate) {
        if (mode == 2) {
            calendar = newDate.withDayOfMonth(1);
            firstLocation = calendar.getDayOfWeek().getValue();
        } else if (mode == 1) {
            calendar = calendar.withMonth(1).withDayOfMonth(1);
        } else if (mode == 0) {
            int offset = calendar.getYear() % 10;
            int firstYear = calendar.getYear() - offset; // 整十年份值
            firstLocation = firstYear % 4; // 首个年份位置
        }
    }

    public void changeOffset(int offset) {
        this.offset = offset;
    }

    @Override
    public int getColumnCount() {
        return mode == 2 ? 7 : 4;
    }

    @Override
    public int getRowCount() {
        return mode == 2 ? 6 : 4;
    }

    @Override
    public Object getValueAt(int row, int column) {
        CellValue cellValue;
        if (mode == 2) {
            column++; // week day 1 start
            int cellIndex = row * 7 + column;
            cellValue = new CellValue(calendar.plusDays(cellIndex - firstLocation + offset * 7));
        } else if (mode == 1) {
            int cellIndex = row * 4 + column + offset * 4;
            cellValue = new CellValue(calendar.plusMonths(cellIndex));
        } else {
            int r = calendar.getYear() % 10;
            int firstYear = calendar.getYear() - r;

            int cellIndex = row * 4 + column - firstLocation + offset * 4;
            cellValue = new CellValue(firstYear + cellIndex, 1, 1);
        }

        cellValue.setMode(mode);
        return cellValue;
    }

    public LocalDate getShowingDate() {
        int rowCount = getRowCount();
        int colCount = getColumnCount();

        List<CellValue> list = new ArrayList<>();
        for (int i = 0; i < rowCount; i++) {
            for (int k = 0; k < colCount; k++) {
                CellValue cellValue = (CellValue) getValueAt(i, k);
                list.add(cellValue);
            }
        }

        int count = 0;
        CellValue target = null;

        if (mode == 2) {
            Map<Integer, List<CellValue>> map = list.stream().collect(Collectors.groupingBy(e -> e.getMonth()));
            for (Map.Entry<Integer, List<CellValue>> entry : map.entrySet()) {
                if (entry.getValue().size() > count) {
                    count = entry.getValue().size();
                    target = entry.getValue().get(0);
                }
            }
        } else if (mode == 1) {
            Map<Integer, List<CellValue>> map = list.stream().collect(Collectors.groupingBy(e -> e.getYear()));
            for (Map.Entry<Integer, List<CellValue>> entry : map.entrySet()) {
                if (entry.getValue().size() > count) {
                    count = entry.getValue().size();
                    target = entry.getValue().get(0);
                }
            }
        } else {
            Map<Integer, List<CellValue>> map = list.stream().collect(Collectors.groupingBy(e -> (e.getYear() / 10) % 10));
            for (Map.Entry<Integer, List<CellValue>> entry : map.entrySet()) {
                if (entry.getValue().size() > count) {
                    count = entry.getValue().size();
                    target = entry.getValue().get(0);
                }
            }
        }

        return target.toLocalDate();
    }
}
